{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# RunModel with Heterogeneous Input: Python model execution\n",
    "\n",
    "The RunModel class is capable of passing input in different formats into a single computational model. This means that the samples passed into a model can be passed as:\n",
    "- floating point values\n",
    "- numpy arrays\n",
    "- lists \n",
    "- tuples\n",
    "- lists of other iterables\n",
    "- numpy arrays of other iterables\n",
    "- or any combination of the above\n",
    "\n",
    "In the examples below, we demonstrate the use of a Python computational model with inputs that are combinations of the above.\n",
    "\n",
    "Some notes on their use:\n",
    "1. UQpy converts all sample input to a numpy array with at least two dimensions. The first dimension, i.e. len(samples) must correspond to the number of samples being passed for model execution. The second dimension, i.e. len(samples[0]) must correspond to the number of variables that each sample possesses.\n",
    "2. Each individual sample, i.e. sample[j], may be composed of multiple data types -- with each variable having a different data type. For example, sample[j][k] may be a floating point value and sample[j][l] may be an array of arbitrary dimension.\n",
    "3. If a specific variable has multiple dimensions, the user may specify the index to be return in the input file. For example, the place holder for a variable x1 corresponding to sample[j][l] that is an array of shape (1,4) can be read as <x1[0, 3]>, which will return the final (0,3) component of samples[j][l].\n",
    "4. If the user does not specify the index for a multidimensional variable, then the entire multidimensional variable is flattened and written with comma delimiters.\n",
    "\n",
    "Michael D. Shields  \n",
    "29 April 2020"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Python Model Summary\n",
    "Examples 1-2:\n",
    "The provided Matlab models take the sum of three random variables:  \n",
    "$s = \\sum_{i=1}^3 x_i$  \n",
    "$x_i \\sim N(0,1)$\n",
    "\n",
    "Example 3:\n",
    "The provided Matlab model takes the product of a random variable and the determinant of a random matrix:  \n",
    "$z = x \\det(Y)$  \n",
    "$x \\sim N(0,1)$  \n",
    "$y$ is a 3x3 matrix of standard normal random variables.\n",
    "\n",
    "The Python model may be provided as either a class or a function. The examples below explore both cases."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from UQpy.SampleMethods import MCS\n",
    "from UQpy.RunModel import RunModel\n",
    "from UQpy.Distributions import Normal\n",
    "import matplotlib.pyplot as plt\n",
    "import time\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pick which model to run\n",
    "Options:\n",
    "- 'all'\n",
    "- 'scalar'\n",
    "- 'vector'\n",
    "- 'mixed'\n",
    "- 'fixed'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "pick_model = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 1: Three scalar random variables\n",
    "In this example, we pass three scalar random variables. Note that this is different from assigning a single variable with three components, which will be handled in the following example. \n",
    "\n",
    "Here we will pass the samples both as an ndarray and as a list. Recall that UQpy converts all samples into an ndarray of at least two dimensions internally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Monte Carlo samples of three random variables from a standard normal distribution.\n",
      "Samples stored as an array:\n",
      "Data type: <class 'numpy.ndarray'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 3)\n",
      "Samples\n",
      "[[ 2.23176466 -0.64178252 -0.38551651]\n",
      " [ 2.39233592  0.23474428  0.89104532]\n",
      " [-0.27088124  0.6625034  -1.66249933]\n",
      " [ 0.1157384  -0.09437841  1.04910279]\n",
      " [ 0.03322176 -0.09323229 -0.45691713]]\n",
      "\n",
      "Samples stored as a list:\n",
      "Data type: <class 'list'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 3)\n",
      "Samples:\n",
      "[array([ 2.23176466, -0.64178252, -0.38551651]), array([2.39233592, 0.23474428, 0.89104532]), array([-0.27088124,  0.6625034 , -1.66249933]), array([ 0.1157384 , -0.09437841,  1.04910279]), array([ 0.03322176, -0.09323229, -0.45691713])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'scalar' or pick_model =='vector' or pick_model == 'all':\n",
    "    # Call MCS to generate samples\n",
    "    # THIS WILL NEED TO BE REWRITTEN WITH DISTRIBUTION AND MCS UPDATES --------------------------------------------\n",
    "#     x_mcs = MCS(dist_name=['Normal','Normal','Normal'], dist_params=[[0,1],[0,1],[0,1]], nsamples=5, \n",
    "#                 var_names = ['var1', 'var11', 'var111']) \n",
    "    # -------------------------------------------------------------------------------------------------------------\n",
    "    # Call MCS to generate samples\n",
    "    d = Normal(loc=0, scale=1)\n",
    "    x_mcs = MCS(dist_object=[d, d, d], nsamples=5, random_state=987979)\n",
    "    names = ['var1', 'var11', 'var111']\n",
    "    \n",
    "    \n",
    "    # UQpy returns samples as an ndarray. Convert them to a list for part 1.2\n",
    "    x_mcs_list = list(x_mcs.samples)\n",
    "    print(\"Monte Carlo samples of three random variables from a standard normal distribution.\")\n",
    "    print('Samples stored as an array:')\n",
    "    print('Data type:', type(x_mcs.samples))\n",
    "    print('Number of samples:', len(x_mcs.samples))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs.samples))\n",
    "    print('Samples')\n",
    "    print(x_mcs.samples)\n",
    "    print()\n",
    "    print('Samples stored as a list:')\n",
    "    print('Data type:', type(x_mcs_list))   \n",
    "    print('Number of samples:', len(x_mcs_list))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs_list))\n",
    "    print('Samples:')\n",
    "    print(x_mcs_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1 Pass samples as ndarray, Python class called, serial execution  \n",
    "This examples uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "UQpy: The following directory has been created for model evaluations: \n",
      "/Users/lohitvandanapu/Documents/GitHub/UQpy/example/RunModel/Python_Example/Python_Runs_2021_04_22_08_18_460212_PM\n",
      "\n",
      "UQpy: The model files have been copied to the following directory for evaluation: \n",
      "/Users/lohitvandanapu/Documents/GitHub/UQpy/example/RunModel/Python_Example/Python_Runs_2021_04_22_08_18_460212_PM\n",
      "\n",
      "UQpy: No samples are provided. Creating the object and building the model directory.\n",
      "\n",
      "\n",
      "UQpy: All model evaluations will be executed from the following directory: \n",
      "/Users/lohitvandanapu/Documents/GitHub/UQpy/example/RunModel/Python_Example/Python_Runs_2021_04_22_08_18_460212_PM\n",
      "\n",
      "UQpy: The model class that will be run: SumRVs\n",
      "\n",
      "UQpy: Performing serial execution of a Python model.\n",
      "\n",
      "\n",
      "UQpy: Serial execution of the python model complete.\n",
      "\n",
      "\n",
      "UQpy: Serial execution of the python model complete.\n",
      "\n",
      "\n",
      "UQpy: Returning to the parent directory:\n",
      "/Users/lohitvandanapu/Documents/GitHub/UQpy/example/RunModel/Python_Example\n",
      "\n",
      "Time for serial execution:\n",
      "0.022784948348999023\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[1.2044656328098802, 3.518125524609024, -1.2708771679901163, 1.0704627778055296, -0.5169276561716473]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'scalar' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m11 = RunModel(ntasks=1, model_script='python_model.py', model_object_name='SumRVs', model_dir='Python_Runs', verbose=True)\n",
    "    m11.run(samples=x_mcs.samples,)\n",
    "    t_ser_python = time.time() - t\n",
    "    print(\"\\nTime for serial execution:\")\n",
    "    print(t_ser_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m11.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 Pass samples as list, Python function called, parallel execution  \n",
    "This examples uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for parallel execution:\n",
      "0.016775846481323242\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[array([1.20446563]), array([3.51812552]), array([-1.27087717]), array([1.07046278]), array([-0.51692766])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'scalar' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m12 = RunModel(samples=x_mcs_list, ntasks=2, model_script='python_model.py', \n",
    "                 model_object_name='sum_rvs', model_dir='Python_Runs')\n",
    "    t_par_python = time.time() - t\n",
    "    print(\"\\nTime for parallel execution:\")\n",
    "    print(t_par_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m12.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 2: Single tri-variate random variable\n",
    "In this example, we pass three random variables in as a trivariate random variable. Note that this is different from assigning three scalar random variables, which was be handled in Example 1.\n",
    "\n",
    "Again, we will pass the samples both as an ndarray and as a list. Recall that UQpy converts all samples into an ndarray of at least two dimensions internally."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Restructure the samples\n",
    "To pass the samples in as a single tri-variate variable, we need reshape the samples from shape (5, 3) to shape (5, 1, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Monte Carlo samples of three random variables from a standard normal distribution.\n",
      "Samples stored as an array:\n",
      "Data type: <class 'numpy.ndarray'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 1, 3)\n",
      "Samples\n",
      "[[[ 2.23176466 -0.64178252 -0.38551651]]\n",
      "\n",
      " [[ 2.39233592  0.23474428  0.89104532]]\n",
      "\n",
      " [[-0.27088124  0.6625034  -1.66249933]]\n",
      "\n",
      " [[ 0.1157384  -0.09437841  1.04910279]]\n",
      "\n",
      " [[ 0.03322176 -0.09323229 -0.45691713]]]\n",
      "\n",
      "Samples stored as a list:\n",
      "Data type: <class 'list'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 1, 3)\n",
      "Samples:\n",
      "[array([[ 2.23176466, -0.64178252, -0.38551651]]), array([[2.39233592, 0.23474428, 0.89104532]]), array([[-0.27088124,  0.6625034 , -1.66249933]]), array([[ 0.1157384 , -0.09437841,  1.04910279]]), array([[ 0.03322176, -0.09323229, -0.45691713]])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'vector' or pick_model == 'all':\n",
    "    x_mcs_tri = x_mcs.samples.reshape(5, 1, 3)\n",
    "    x_mcs_tri_list = list(x_mcs_tri)\n",
    "\n",
    "    print(\"Monte Carlo samples of three random variables from a standard normal distribution.\")\n",
    "    print('Samples stored as an array:')\n",
    "    print('Data type:', type(x_mcs_tri))\n",
    "    print('Number of samples:', len(x_mcs_tri))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs_tri))\n",
    "    print('Samples')\n",
    "    print(x_mcs_tri)\n",
    "    print()\n",
    "    print('Samples stored as a list:')\n",
    "    print('Data type:', type(x_mcs_tri_list))   \n",
    "    print('Number of samples:', len(x_mcs_tri_list))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs_tri_list))\n",
    "    print('Samples:')\n",
    "    print(x_mcs_tri_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1 Pass samples as ndarray, Python function called, serial execution\n",
    "This example uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for serial execution:\n",
      "0.00709080696105957\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[array([1.20446563]), array([3.51812552]), array([-1.27087717]), array([1.07046278]), array([-0.51692766])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'vector' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m21 = RunModel(samples=x_mcs_tri, ntasks=1, model_script='python_model.py', \n",
    "                 model_object_name='sum_rvs_vec', model_dir='Python_Runs')\n",
    "    t_ser_python = time.time() - t\n",
    "    print(\"\\nTime for serial execution:\")\n",
    "    print(t_ser_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m21.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 Pass samples as list, Python class called, parallel execution\n",
    "This example uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for parallel execution:\n",
      "0.01832294464111328\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[array([1.20446563]), array([3.51812552]), array([-1.27087717]), array([1.07046278]), array([-0.51692766])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'vector' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m22 = RunModel(samples=x_mcs_tri_list, ntasks=2, model_script='python_model.py', \n",
    "                 model_object_name='SumRVs', model_dir='Python_Runs')\n",
    "    t_par_python = time.time() - t\n",
    "    print(\"\\nTime for parallel execution:\")\n",
    "    print(t_par_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m22.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 3: Passing a scalar and an array to RunModel\n",
    "In this example, we pass a single scalar random variable as well as an array into a Matlab model.\n",
    "\n",
    "Again, we will pass the samples both as an ndarray and as a list. Recall that UQpy converts all samples into an ndarray of at least two dimensions internally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Monte Carlo samples of a single random variable from a standard normal distribution.\n",
      "Samples stored as an array:\n",
      "Data type: <class 'numpy.ndarray'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 1)\n",
      "Samples\n",
      "[[ 2.23176466]\n",
      " [ 2.39233592]\n",
      " [-0.27088124]\n",
      " [ 0.1157384 ]\n",
      " [ 0.03322176]]\n",
      "\n",
      "Monte Carlo samples of a 3x3 matrix of standard normal random variables.\n",
      "Samples stored as an array:\n",
      "Data type: <class 'numpy.ndarray'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 3, 3)\n",
      "Samples\n",
      "[[[ 1.41844416e-01  3.02388356e-01 -1.23439338e+00]\n",
      "  [ 7.20992367e-01  1.52119064e+00  3.89663401e-01]\n",
      "  [-8.41732889e-01  6.22714399e-01  4.81666741e-01]]\n",
      "\n",
      " [[-6.44218784e-01 -1.15450313e+00 -1.13456854e+00]\n",
      "  [ 1.19971101e+00  3.80664178e-02 -8.49111812e-02]\n",
      "  [-5.62372993e-01  1.02606814e+00  4.24392486e-01]]\n",
      "\n",
      " [[-1.47495390e+00 -1.83639697e-05  1.03667812e-01]\n",
      "  [ 3.67230456e-01  4.43218583e-01  2.19753402e-01]\n",
      "  [ 1.68307016e+00  6.50639674e-02  1.73664803e+00]]\n",
      "\n",
      " [[ 8.12629703e-01 -7.34797593e-01 -4.92923798e-01]\n",
      "  [-6.03117372e-01  1.84220244e+00  6.86679520e-02]\n",
      "  [-6.17815065e-01  1.38407753e-01 -1.02776267e+00]]\n",
      "\n",
      " [[-7.73687187e-01 -1.14836191e+00 -6.79684240e-01]\n",
      "  [-9.67105857e-01 -1.31879204e+00  4.76126420e-01]\n",
      "  [-2.94287448e-01 -1.70578952e-01  1.24595246e-01]]]\n",
      "\n",
      "Combined samples with a scalar and a 3x3 matrix of standard normal random variables.\n",
      "Samples stored as a list:\n",
      "Data type: <class 'list'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 2)\n",
      "Samples\n",
      "[[array([2.23176466]), array([[ 0.14184442,  0.30238836, -1.23439338],\n",
      "       [ 0.72099237,  1.52119064,  0.3896634 ],\n",
      "       [-0.84173289,  0.6227144 ,  0.48166674]])], [array([2.39233592]), array([[-0.64421878, -1.15450313, -1.13456854],\n",
      "       [ 1.19971101,  0.03806642, -0.08491118],\n",
      "       [-0.56237299,  1.02606814,  0.42439249]])], [array([-0.27088124]), array([[-1.47495390e+00, -1.83639697e-05,  1.03667812e-01],\n",
      "       [ 3.67230456e-01,  4.43218583e-01,  2.19753402e-01],\n",
      "       [ 1.68307016e+00,  6.50639674e-02,  1.73664803e+00]])], [array([0.1157384]), array([[ 0.8126297 , -0.73479759, -0.4929238 ],\n",
      "       [-0.60311737,  1.84220244,  0.06866795],\n",
      "       [-0.61781506,  0.13840775, -1.02776267]])], [array([0.03322176]), array([[-0.77368719, -1.14836191, -0.67968424],\n",
      "       [-0.96710586, -1.31879204,  0.47612642],\n",
      "       [-0.29428745, -0.17057895,  0.12459525]])]]\n",
      "\n",
      "Combined samples with a scalar and a 3x3 matrix of standard normal random variables.\n",
      "Samples stored as ndarray:\n",
      "Data type: <class 'numpy.ndarray'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 2)\n",
      "Samples\n",
      "[[array([2.23176466])\n",
      "  array([[ 0.14184442,  0.30238836, -1.23439338],\n",
      "       [ 0.72099237,  1.52119064,  0.3896634 ],\n",
      "       [-0.84173289,  0.6227144 ,  0.48166674]])]\n",
      " [array([2.39233592])\n",
      "  array([[-0.64421878, -1.15450313, -1.13456854],\n",
      "       [ 1.19971101,  0.03806642, -0.08491118],\n",
      "       [-0.56237299,  1.02606814,  0.42439249]])]\n",
      " [array([-0.27088124])\n",
      "  array([[-1.47495390e+00, -1.83639697e-05,  1.03667812e-01],\n",
      "       [ 3.67230456e-01,  4.43218583e-01,  2.19753402e-01],\n",
      "       [ 1.68307016e+00,  6.50639674e-02,  1.73664803e+00]])]\n",
      " [array([0.1157384])\n",
      "  array([[ 0.8126297 , -0.73479759, -0.4929238 ],\n",
      "       [-0.60311737,  1.84220244,  0.06866795],\n",
      "       [-0.61781506,  0.13840775, -1.02776267]])]\n",
      " [array([0.03322176])\n",
      "  array([[-0.77368719, -1.14836191, -0.67968424],\n",
      "       [-0.96710586, -1.31879204,  0.47612642],\n",
      "       [-0.29428745, -0.17057895,  0.12459525]])]]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'mixed' or pick_model =='vector' or pick_model == 'all':\n",
    "    # Call MCS to generate samples\n",
    "    # THIS WILL NEED TO BE REWRITTEN WITH DISTRIBUTION AND MCS UPDATES --------------------------------------------\n",
    "    # First generate the scalar random variable\n",
    "#     x_mcs1 = MCS(dist_name=['Normal'], dist_params=[[0,1]], nsamples=5, var_names = ['var1']) \n",
    "    # Next generate a 3x3 random matrix\n",
    "#     x_mcs2 = MCS(dist_name=['Normal','Normal','Normal'], dist_params=[[0,1],[0,1],[0,1]], nsamples=15)\n",
    "#     x_mcs_array = x_mcs2.samples.reshape((5,3,3))\n",
    "    # -------------------------------------------------------------------------------------------------------------\n",
    "    \n",
    "    # Call MCS to generate samples\n",
    "    d = Normal(loc=0, scale=1)\n",
    "    x_mcs1 = MCS(dist_object=d, nsamples=5, random_state=987979)\n",
    "    x_mcs2 = MCS(dist_object=[d, d, d], nsamples=15, random_state=34876)\n",
    "    x_mcs_array = x_mcs2.samples.reshape((5,3,3))\n",
    "    \n",
    "    print(\"Monte Carlo samples of a single random variable from a standard normal distribution.\")\n",
    "    print('Samples stored as an array:')\n",
    "    print('Data type:', type(x_mcs1.samples))\n",
    "    print('Number of samples:', len(x_mcs1.samples))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs1.samples))\n",
    "    print('Samples')\n",
    "    print(x_mcs1.samples)\n",
    "    print()\n",
    "    print(\"Monte Carlo samples of a 3x3 matrix of standard normal random variables.\")\n",
    "    print('Samples stored as an array:')\n",
    "    print('Data type:', type(x_mcs_array))\n",
    "    print('Number of samples:', len(x_mcs_array))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs_array))\n",
    "    print('Samples')\n",
    "    print(x_mcs_array)\n",
    "    print()\n",
    "    \n",
    "    # Create a set of samples to be passed into RunModel\n",
    "    # Here we need to create the mixed samples such that each sample has a single scalar and a single 3x3 matrix.\n",
    "    # This data structure is essential to passing the input to UQpy correctly.\n",
    "    x_mixed = []\n",
    "    for i in range(5):\n",
    "        x_mixed.append([x_mcs1.samples[i], x_mcs_array[i]])\n",
    "        \n",
    "    print(\"Combined samples with a scalar and a 3x3 matrix of standard normal random variables.\")\n",
    "    print('Samples stored as a list:')\n",
    "    print('Data type:', type(x_mixed))\n",
    "    print('Number of samples:', len(x_mixed))\n",
    "    print('Dimensions of samples:', np.shape(x_mixed))\n",
    "    print('Samples')\n",
    "    print(x_mixed)\n",
    "    print()\n",
    "    \n",
    "    x_mixed_array = np.atleast_2d(np.asarray(x_mixed))\n",
    "    print(\"Combined samples with a scalar and a 3x3 matrix of standard normal random variables.\")\n",
    "    print('Samples stored as ndarray:')\n",
    "    print('Data type:', type(x_mixed_array))\n",
    "    print('Number of samples:', len(x_mixed_array))\n",
    "    print('Dimensions of samples:', np.shape(x_mixed_array))\n",
    "    print('Samples')\n",
    "    print(x_mixed_array)\n",
    "    print()\n",
    "    \n",
    "    # Notice that, in both the ndarray case and the list case, the samples have dimension (5,2). That is, there\n",
    "    # are five samples of two variables. The first variable is a scalar. The second variable is a 3x3 matrix."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 Pass samples as ndarray, Python class called, serial execution \n",
    "This examples uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for serial execution:\n",
      "0.011285781860351562\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[array([-5.06488369]), array([-2.28414587]), array([0.32209288]), array([-0.18281303]), array([0.00792293])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'mixed' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m31 = RunModel(samples=x_mixed_array, ntasks=1, model_script='python_model.py', \n",
    "                 model_object_name='DetRVs', model_dir='Python_Runs', vec=False)\n",
    "    t_ser_python = time.time() - t\n",
    "    print(\"\\nTime for serial execution:\")\n",
    "    print(t_ser_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m31.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 Pass samples as list, Python function called, parallel execution \n",
    "This examples uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for parallel execution:\n",
      "0.007647037506103516\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[array([-5.06488369]), array([-2.28414587]), array([0.32209288]), array([-0.18281303]), array([0.00792293])]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'mixed' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    # Note that the parallel model_object handles only one sample at a time.\n",
    "    t = time.time()\n",
    "    m32 = RunModel(samples=x_mixed, ntasks=1, model_script='python_model.py', \n",
    "                 model_object_name='det_rvs_par', model_dir='Python_Runs', vec=False)\n",
    "    t_par_python = time.time() - t\n",
    "    print(\"\\nTime for parallel execution:\")\n",
    "    print(t_par_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m32.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 4: Passing a fixed variable and an array of Random Variables to RunModel\n",
    "In this example, we pass a fixed value coefficient as well as an array of random variables into a Python model.\n",
    "\n",
    "Again, we will pass the samples both as an ndarray and as a list. Recall that UQpy converts all samples into an ndarray of at least two dimensions internally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Constant Coefficient:\n",
      "2.5\n",
      "\n",
      "Monte Carlo samples of a 3x3 matrix of standard normal random variables.\n",
      "Samples stored as an array:\n",
      "Data type: <class 'numpy.ndarray'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 3, 3)\n",
      "Samples\n",
      "[[[ 1.41844416e-01  3.02388356e-01 -1.23439338e+00]\n",
      "  [ 7.20992367e-01  1.52119064e+00  3.89663401e-01]\n",
      "  [-8.41732889e-01  6.22714399e-01  4.81666741e-01]]\n",
      "\n",
      " [[-6.44218784e-01 -1.15450313e+00 -1.13456854e+00]\n",
      "  [ 1.19971101e+00  3.80664178e-02 -8.49111812e-02]\n",
      "  [-5.62372993e-01  1.02606814e+00  4.24392486e-01]]\n",
      "\n",
      " [[-1.47495390e+00 -1.83639697e-05  1.03667812e-01]\n",
      "  [ 3.67230456e-01  4.43218583e-01  2.19753402e-01]\n",
      "  [ 1.68307016e+00  6.50639674e-02  1.73664803e+00]]\n",
      "\n",
      " [[ 8.12629703e-01 -7.34797593e-01 -4.92923798e-01]\n",
      "  [-6.03117372e-01  1.84220244e+00  6.86679520e-02]\n",
      "  [-6.17815065e-01  1.38407753e-01 -1.02776267e+00]]\n",
      "\n",
      " [[-7.73687187e-01 -1.14836191e+00 -6.79684240e-01]\n",
      "  [-9.67105857e-01 -1.31879204e+00  4.76126420e-01]\n",
      "  [-2.94287448e-01 -1.70578952e-01  1.24595246e-01]]]\n",
      "\n",
      "3x3 matrix of standard normal random variables.\n",
      "Samples stored as ndarray:\n",
      "Data type: <class 'list'>\n",
      "Number of samples: 5\n",
      "Dimensions of samples: (5, 3, 3)\n",
      "Samples\n",
      "[array([[ 0.14184442,  0.30238836, -1.23439338],\n",
      "       [ 0.72099237,  1.52119064,  0.3896634 ],\n",
      "       [-0.84173289,  0.6227144 ,  0.48166674]]), array([[-0.64421878, -1.15450313, -1.13456854],\n",
      "       [ 1.19971101,  0.03806642, -0.08491118],\n",
      "       [-0.56237299,  1.02606814,  0.42439249]]), array([[-1.47495390e+00, -1.83639697e-05,  1.03667812e-01],\n",
      "       [ 3.67230456e-01,  4.43218583e-01,  2.19753402e-01],\n",
      "       [ 1.68307016e+00,  6.50639674e-02,  1.73664803e+00]]), array([[ 0.8126297 , -0.73479759, -0.4929238 ],\n",
      "       [-0.60311737,  1.84220244,  0.06866795],\n",
      "       [-0.61781506,  0.13840775, -1.02776267]]), array([[-0.77368719, -1.14836191, -0.67968424],\n",
      "       [-0.96710586, -1.31879204,  0.47612642],\n",
      "       [-0.29428745, -0.17057895,  0.12459525]])]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'mixed' or pick_model == 'all':\n",
    "    x = 2.5\n",
    "    \n",
    "    print('Constant Coefficient:')\n",
    "    print(x)\n",
    "    print()\n",
    "    \n",
    "    print(\"Monte Carlo samples of a 3x3 matrix of standard normal random variables.\")\n",
    "    print('Samples stored as an array:')\n",
    "    print('Data type:', type(x_mcs_array))\n",
    "    print('Number of samples:', len(x_mcs_array))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs_array))\n",
    "    print('Samples')\n",
    "    print(x_mcs_array)\n",
    "    print()\n",
    "    \n",
    "    x_mcs_list = list(x_mcs_array)\n",
    "\n",
    "    print(\"3x3 matrix of standard normal random variables.\")\n",
    "    print('Samples stored as ndarray:')\n",
    "    print('Data type:', type(x_mcs_list))\n",
    "    print('Number of samples:', len(x_mcs_list))\n",
    "    print('Dimensions of samples:', np.shape(x_mcs_list))\n",
    "    print('Samples')\n",
    "    print(x_mcs_list)\n",
    "    print()\n",
    "    \n",
    "    # Notice that, in both the ndarray case and the list case, the samples have dimension (5,2). That is, there\n",
    "    # are five samples of two variables. The first variable is a scalar. The second variable is a 3x3 matrix."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1 Pass samples as ndarray, Python class called, serial execution \n",
    "This examples uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for serial execution:\n",
      "0.00769805908203125\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[-5.673631015232223, -2.3869409943327016, -2.9726392645350614, -3.948841380481718, 0.5962156121663712]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'mixed' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m41 = RunModel(samples=x_mcs_array, ntasks=1, model_script='python_model.py', \n",
    "                 model_object_name='det_rvs_fixed', model_dir='Python_Runs', vec=False, coeff=x)\n",
    "    t_ser_python = time.time() - t\n",
    "    print(\"\\nTime for serial execution:\")\n",
    "    print(t_ser_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m41.qoi_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 Pass samples as list, Python class called, serial execution \n",
    "This examples uses the following files:\n",
    "- model_script = python_model.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Time for serial execution:\n",
      "0.00405573844909668\n",
      "\n",
      "The values returned from the Matlab simulation:\n",
      "[-5.673631015232223, -2.3869409943327016, -2.9726392645350614, -3.948841380481718, 0.5962156121663712]\n"
     ]
    }
   ],
   "source": [
    "if pick_model == 'mixed' or pick_model == 'all':\n",
    "    # Call to RunModel - Here we run the model while instantiating the RunModel object. \n",
    "    t = time.time()\n",
    "    m42 = RunModel(samples=x_mcs_list, ntasks=1, model_script='python_model.py', \n",
    "                 model_object_name='det_rvs_fixed', model_dir='Python_Runs', vec=False, coeff=x)\n",
    "    t_ser_python = time.time() - t\n",
    "    print(\"\\nTime for serial execution:\")\n",
    "    print(t_ser_python)\n",
    "    print()\n",
    "    print(\"The values returned from the Matlab simulation:\")\n",
    "    print(m42.qoi_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
